THREE.PanoControls = function(camera, domElement, material) {
    this.camera = camera;
    camera.target = new THREE.Vector3();
    this.target = camera.target;
    this.domElement = (domElement !== undefined) ? domElement : document;

    this.autoRotate = false; //是否允许自动旋转
    this.isUserInteracting = false; //是否在交互过程中
    this.isDragPanoImage = false; //是否允许拖拽载入全景

    this.enableDamping = true;
    this.dampingFactor = 0.15;
    var sphericalDelta = new THREE.Spherical();

    var onMouseDownMouseX = 0,
        onMouseDownMouseY = 0,
        lon = 0,
        onMouseDownLon = 0,
        lat = 0,
        onMouseDownLat = 0,
        phi = 0,
        theta = 0;
    var rotateSpeed = 0.1;
    var zoomSpeed = 1;
    var minZoom = 10;
    var maxZoom = 75;

    var dollyStart = new THREE.Vector2();
    var dollyEnd = new THREE.Vector2();
    var dollyDelta = new THREE.Vector2();



    var scope = this;
    //

    function onPointerStart(event) {
        event.preventDefault();

        scope.isUserInteracting = true;

        var clientX = event.clientX || event.touches[0].clientX;
        var clientY = event.clientY || event.touches[0].clientY;

        onMouseDownMouseX = clientX;
        onMouseDownMouseY = clientY;

        onMouseDownLon = lon;
        onMouseDownLat = lat;

    }

    function onPointerMove(event) {
        event.preventDefault();

        if (scope.isUserInteracting === true) {

            var clientX = event.clientX || event.touches[0].clientX;
            var clientY = event.clientY || event.touches[0].clientY;

            lon = (onMouseDownMouseX - clientX) * rotateSpeed + onMouseDownLon;
            lat = (clientY - onMouseDownMouseY) * rotateSpeed + onMouseDownLat;

        }

    }

    function onPointerUp() {

        scope.isUserInteracting = false;

    }

    function onDocumentMouseWheel(event) {

        var fov = scope.camera.fov + event.deltaY * 0.05 * zoomSpeed;

        scope.camera.fov = THREE.Math.clamp(fov, minZoom, maxZoom);

        scope.camera.updateProjectionMatrix();

    }

    function onTouchStart(event) {
        event.preventDefault();

        switch (event.touches.length) {
            case 1:
                scope.isUserInteracting = true;

                var clientX = event.clientX || event.touches[0].clientX;
                var clientY = event.clientY || event.touches[0].clientY;

                onMouseDownMouseX = clientX;
                onMouseDownMouseY = clientY;

                onMouseDownLon = lon;
                onMouseDownLat = lat;
                break;
            case 2:

                scope.isUserInteracting = true;
                var dx = event.touches[0].pageX - event.touches[1].pageX;
                var dy = event.touches[0].pageY - event.touches[1].pageY;

                var distance = Math.sqrt(dx * dx + dy * dy);
                dollyStart.set(0, distance);
                break;
        }
    }

    function onTouchMove(event) {
        event.preventDefault();
        event.stopPropagation();

        switch (event.touches.length) {
            case 1:
                if (scope.isUserInteracting === true) {

                    var clientX = event.clientX || event.touches[0].clientX;
                    var clientY = event.clientY || event.touches[0].clientY;

                    lon = (onMouseDownMouseX - clientX) * rotateSpeed + onMouseDownLon;
                    lat = (clientY - onMouseDownMouseY) * rotateSpeed + onMouseDownLat;

                }
                break;
            case 2:
                if (scope.isUserInteracting === true) {
                    var dx = event.touches[0].pageX - event.touches[1].pageX;
                    var dy = event.touches[0].pageY - event.touches[1].pageY;

                    var distance = Math.sqrt(dx * dx + dy * dy);

                    dollyEnd.set(0, distance);

                    dollyDelta.subVectors(dollyEnd, dollyStart);

                    var fov = scope.camera.fov - dollyDelta.y * 0.05 * zoomSpeed;

                    scope.camera.fov = THREE.Math.clamp(fov, minZoom, maxZoom);

                    scope.camera.updateProjectionMatrix();

                    dollyStart.copy(dollyEnd);
                }
                break;

        }


    }

    function onTouchEnd(event) {
        scope.isUserInteracting = false;
    }


    //
    scope.domElement.addEventListener('dragover', function(event) {
        if (!scope.isDragPanoImage) return;
        event.preventDefault();
        event.dataTransfer.dropEffect = 'copy';

    }, false);

    scope.domElement.addEventListener('dragenter', function() {
        if (!scope.isDragPanoImage) return;

        document.body.style.opacity = 0.5;

    }, false);

    scope.domElement.addEventListener('dragleave', function() {
        if (!scope.isDragPanoImage) return;

        document.body.style.opacity = 1;

    }, false);

    scope.domElement.addEventListener('drop', function(event) {
        if (!scope.isDragPanoImage) return;

        event.preventDefault();

        var reader = new FileReader();
        reader.addEventListener('load', function(event) {

            material.map.image.src = event.target.result;
            material.map.needsUpdate = true;

        }, false);
        reader.readAsDataURL(event.dataTransfer.files[0]);

        document.body.style.opacity = 1;

    }, false);

    scope.domElement.addEventListener('mousedown', onPointerStart, false);
    scope.domElement.addEventListener('mousemove', onPointerMove, false);
    scope.domElement.addEventListener('mouseup', onPointerUp, false);

    scope.domElement.addEventListener('wheel', onDocumentMouseWheel, false);

    scope.domElement.addEventListener('touchstart', onTouchStart, false);
    scope.domElement.addEventListener('touchmove', onTouchMove, false);
    scope.domElement.addEventListener('touchend', onTouchEnd, false);


    this.dispose = function() {
        scope.domElement.removeEventListener('mousedown', onPointerStart, false);
        scope.domElement.removeEventListener('mousemove', onPointerMove, false);
        scope.domElement.removeEventListener('mouseup', onPointerUp, false);

        scope.domElement.removeEventListener('wheel', onDocumentMouseWheel, false);

        scope.domElement.removeEventListener('touchstart', onTouchStart, false);
        scope.domElement.removeEventListener('touchmove', onTouchMove, false);
        scope.domElement.removeEventListener('touchend', onTouchEnd, false);
    }

    this.update = function() {

        if (scope.isUserInteracting === false && scope.autoRotate) {

            lon += 0.1;
            lon = lon % 360;

        }

        lat = Math.max(-85, Math.min(85, lat));
        phi = THREE.Math.degToRad(90 - lat);
        theta = THREE.Math.degToRad(lon);

        if (scope.enableDamping === true) {
            sphericalDelta.theta *= (1 - scope.dampingFactor);
            sphericalDelta.phi *= (1 - scope.dampingFactor);
        } else {
            sphericalDelta.set(0, 0, 0);
        }

        phi += sphericalDelta.phi;
        theta += sphericalDelta.theta;

        scope.camera.target.x = 500 * Math.sin(phi) * Math.cos(theta);
        scope.camera.target.y = 500 * Math.cos(phi);
        scope.camera.target.z = 500 * Math.sin(phi) * Math.sin(theta);

        // scope.camera.target.x = 500 * Math.sin(phi) * Math.cos(theta);
        // scope.camera.target.y = 500 * Math.sin(phi) * Math.sin(theta);
        // scope.camera.target.z = 500 * Math.cos(phi);


        scope.camera.lookAt(camera.target);

    }

}